home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
telecomm
/
sticpsrc.lzh
/
SOURCE.ARC
/
PC_TNC2.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-05-03
|
11KB
|
382 lines
/* Support routines for TNC2 emulator - PC version */
#include "global.h"
#include "asy.h"
#include "ax25.h"
#include "timer.h"
#include "slip.h"
#include "tnc2.h"
#define PIPEBUF 512 /* size of a pipe buffer */
#define FLOW_LOW 64 /* low-water mark */
#define FLOW_HIGH 480 /* high-water mark */
/* INT14 vector stored at a second location for use under DoubleDOS */
/* This location is at the end of the "intra-application comm area" */
static void (*far *int14vec)() = (void (*far *)()) 0x000004fcL;
static char tnc2installed = 0; /* vector already set? */
extern void (*far tnc2ovec)(); /* location to store old int14 vec */
extern char nospace[];
/* routine that simulates a character device to the client */
/* this one is called from an INT14 replacement, in the context */
/* of the client! so don't call to many other routines, and don't */
/* try to create pointers to variables in the stack!! (SS != DS) */
/* the parameters are the registers pushed by the assembly language */
/* routine, and it will pop them back on return. if returnval=0, it will */
/* jump to the original handler (to handle other ports) */
/* entry conditions: AH=function code AL=char or param DX=port (from 0) */
/* exit conditions: AX=return value HDL=handler code */
int
int14(di,dx,cx,bx,ax,ds,es)
unsigned short di,dx,cx,bx,ax,ds,es;
{
register struct tnc *tnc2;
int i;
for (tnc2 = tnc2s; tnc2 != NULLTNC; tnc2 = tnc2->next)
if (tnc2->dev == dx + 1) /* this one handled by us? */
break;
if (tnc2 == NULLTNC) /* when not found... */
return 0; /* let someone else deal with it */
switch (ax >> 8) /* switch on function code */
{
case 1: /* Send character */
i = 250;
while (((!(tnc2->status & TS_TXBUF) && /* not allowed to buffer? */
tnc2->input.num != 0) || /* already something there */
tnc2->input.num == PIPEBUF) && /* buffer full? */
--i) /* not the max tries? */
giveup(); /* give NET a chance to read */
if (tnc2->input.num == PIPEBUF) { /* (still) full? */
tnc2->status |= TS_RXOVR; /* then we have an overrun */
ax = 0x8000 | (ax & 0xff); /* 'timeout' error + char */
goto rxstatus; /* plus the receiver status */
}
*tnc2->input.in++ = uchar(ax); /* save the character */
if (tnc2->input.in == tnc2->input.end)
tnc2->input.in = tnc2->input.begin;
if (++(tnc2->input.num) >= FLOW_HIGH)
tnc2->status |= TS_RXSTOP;
/* finally, return the status in AH and sent char in AL */
ax &= 0xff; /* keep only char */
goto trxstatus;
case 2: /* Receive character */
i = 50;
while (tnc2->output.num == 0 && --i) /* no char(s) in buffer? */
giveup();
if (tnc2->output.num == 0){ /* still nothing? */
ax = 0x8048 | (tnc2->status & TS_DCD); /* 'timeout' error */
goto trxstatus;
}
ax = uchar(*tnc2->output.out++); /* AL is received char */
if (tnc2->output.out == tnc2->output.end)
tnc2->output.out = tnc2->output.begin;
if (--(tnc2->output.num) < FLOW_LOW)
tnc2->status &= ~TS_TXSTOP;
goto trxstatus; /* add tx & rx status in AH */
case 0: /* Initialize */
/* flush the input and output buffers */
tnc2->input.in = tnc2->input.out = tnc2->input.begin;
tnc2->input.num = 0;
tnc2->output.in = tnc2->output.out = tnc2->output.begin;
tnc2->output.num = 0;
/* keep only the DCD and TXBUF bits in the status (rest is volatile) */
tnc2->status &= TS_DCD | TS_TXBUF;
/* return status like: */
case 3: /* Status request */
allstatus:
if (tnc2->input.num != 0 && /* something in buffer? */
!(tnc2->status & TS_TXBUF)) /* not allowed to buffer? */
giveup(); /* let NET read the char now */
ax = 0x0048 | (tnc2->status & TS_DCD); /* default status = DSR DDCD */
if (tnc2->input.num < FLOW_LOW || /* below flow control treshold? */
(!(tnc2->status & TS_RXSTOP) && tnc2->input.num < FLOW_HIGH))
ax |= 0x10; /* turn on CTS */
trxstatus:
if (tnc2->input.num == 0) /* buffer empty? */
ax |= 0x6000; /* then turn on TEMT and THRE */
if ((tnc2->status & TS_TXBUF) && /* allowed to buffer? */
tnc2->input.num < PIPEBUF) /* buffer not yet full? */
ax |= 0x2000; /* then turn on THRE */
rxstatus:
if (tnc2->output.num != 0) /* char(s) in buffer? */
ax |= 0x0100; /* turn on data ready */
if (tnc2->status & TS_TXOVR) { /* transmitter overrun? */
tnc2->status &= ~TS_TXOVR;
ax |= 0x0200; /* turn on overrun error */
}
break;
case 4: /* Inquiry */
ax = 0xaa55; /* Return AA55 to caller */
break;
case 5: /* Drop DTR & RTS (MBBIOS) */
tnc2->status |= TS_TXHOLD;
goto allstatus;
case 6: /* Raise DTR & RTS (MBBIOS) */
tnc2->status &= ~TS_TXHOLD;
goto allstatus;
case 7: /* Send Break (MBBIOS) */
i = 150; /* First allow buffer to drain */
while (tnc2->output.num != 0 && --i) /* char(s) in buffer? */
giveup();
tnc2->status |= TS_BREAK; /* set the "BREAK Received" flag */
goto allstatus;
case 8: /* Non-destr Read (MBBIOS) */
ax = uchar(*tnc2->output.out); /* AL is next char */
goto trxstatus; /* add tx & rx status in AH */
case 9: /* Set/Get Options (MBBIOS 3.2) */
if (ax & TS_TXBUF) { /* Only support TX Buf switching */
ax = 0x44 | (tnc2->status & TS_TXBUF); /* Highspeed/HW Handshake/TX Buffering */
tnc2->status |= TS_TXBUF;
} else {
ax = 0x44 | (tnc2->status & TS_TXBUF); /* Highspeed/HW Handshake/TX Buffering */
tnc2->status &= ~TS_TXBUF;
}
break;
case 10: /* Write Buffer (MBBIOS 3.2) */
while (cx != 0 && /* more to go? */
tnc2->input.num != PIPEBUF) { /* buffer not full? */
*tnc2->input.in++ = ((char far *) ((long) es << 16))[di++];
if (tnc2->input.in == tnc2->input.end)
tnc2->input.in = tnc2->input.begin;
if (++(tnc2->input.num) >= FLOW_HIGH)
tnc2->status |= TS_RXSTOP;
cx--;
}
goto allstatus;
case 11: /* Read Buffer (MBBIOS 3.2) */
i = cx; /* move bytecount to temp */
cx = 0; /* number of bytes done */
while (i-- && tnc2->output.num != 0) { /* more requested & more available */
((char far *) ((long) es << 16))[di++] = *tnc2->output.out++;
if (tnc2->output.out == tnc2->output.end)
tnc2->output.out = tnc2->output.begin;
if (--(tnc2->output.num) < FLOW_LOW)
tnc2->status &= ~TS_TXSTOP;
cx++;
}
goto allstatus;
default: /* Unrecognized request */
ax = 0; /* Let's just return 0 */
break;
}
return 1; /* we've handled it! */
}
/* public routines for use by tnc2 emulator */
/* initialize TNC2 client port */
int
tnc2_init (tnc2)
register struct tnc *tnc2;
{
extern void tnc2vec();
#ifndef __TURBOC__
void (*getvect())();
#endif
#ifdef COMBIOS
unsigned int dev = tnc2->dev - 1; /* BIOS-compat dev */
#endif
tnc2->status = 0; /* Unbuffered, all OFF */
#ifdef COMBIOS
/* check if it is a BIOS-supported port, and assume external port if so */
if (dev < ASY_MAX && combios(0x00e3,dev) != 0x00e3){
if (com_init(dev) || com_speed(dev,9600,"h"))
return 1;
return 0;
}
#endif
if ((tnc2->input.begin = malloc(PIPEBUF)) == NULLCHAR){
printf(nospace);
return 1;
}
tnc2->input.in = tnc2->input.out = tnc2->input.begin;
tnc2->input.end = tnc2->input.begin + PIPEBUF;
tnc2->input.num = 0;
if ((tnc2->output.begin = malloc(PIPEBUF)) == NULLCHAR){
free(tnc2->input.begin);
printf(nospace);
return 1;
}
tnc2->output.in = tnc2->output.out = tnc2->output.begin;
tnc2->output.end = tnc2->output.begin + PIPEBUF;
tnc2->output.num = 0;
if (!tnc2installed) { /* not yet installed? */
tnc2ovec = getvect(0x14); /* save existing vector */
setvect(0x14,tnc2vec); /* install our handler */
*int14vec = tnc2vec; /* save a second time */
tnc2installed = 1;
}
return 0;
}
/* terminate TNC2 client port */
void
tnc2_term